package setting

import (
	"fmt"
	"log"

	"github.com/fsnotify/fsnotify"
	"github.com/spf13/viper"
)

// Conf 定义配置的全局变量
var Conf = new(AppConfig)

type AppConfig struct {
	Name      string `mapstructure:"name"`
	Mode      string `mapstructure:"mode"`
	Version   string `mapstructure:"version"`
	StartTime string `mapstructure:"start_time"`
	MachineID int64  `mapstructure:"machine_id"`
	Port      int    `mapstructure:"port"`

	*LogConfig   `mapstructure:"log"`
	*MySQLConfig `mapstructure:"mysql"`
	*RedisConfig `mapstructure:"redis"`
	*CorsConfig  `mapstructure:"cors"`
}

type CorsConfig struct {
	AllowAllOrigins bool     `mapstructure:"allow_all_Origins"`
	AllowOrigins    []string `mapstructure:"allow_origins"`
	AllowHeaders    []string `mapstructure:"allow_headers"`
	ExposeHeaders   []string `mapstructure:"expose_headers"`
}

type MySQLConfig struct {
	Host         string `mapstructure:"host"`
	User         string `mapstructure:"user"`
	Password     string `mapstructure:"password"`
	DB           string `mapstructure:"db"`
	Port         int    `mapstructure:"port"`
	MaxOpenConns int    `mapstructure:"max_open_conns"`
	MaxIdleConns int    `mapstructure:"max_idle_conns"`
}

type RedisConfig struct {
	Host         string `mapstructure:"host"`
	Password     string `mapstructure:"password"`
	Port         int    `mapstructure:"port"`
	DB           int    `mapstructure:"db"`
	PoolSize     int    `mapstructure:"pool_size"`
	MinIdleConns int    `mapstructure:"min_idle_conns"`
}

type LogConfig struct {
	Level      string `mapstructure:"level"`
	Filename   string `mapstructure:"filename"`
	MaxSize    int    `mapstructure:"max_size"`
	MaxAge     int    `mapstructure:"max_age"`
	MaxBackups int    `mapstructure:"max_backups"`
}

const PathKey = "PROFILE_PATH"

// Init init config.
func Init(filePath string) (err error) {
	if envFilePath := GetEnvInfo(PathKey); envFilePath != "" {
		filePath = envFilePath
	}

	// 指定配置文件路径
	viper.SetConfigFile(filePath)
	// 读取配置信息
	err = viper.ReadInConfig()
	if err != nil {
		// 读取配置信息失败
		return fmt.Errorf("viper read config failed, err:%v\n", err)
	}

	// 把读取到的配置信息反序列化到 Conf 变量中
	if err := viper.Unmarshal(Conf); err != nil {
		return fmt.Errorf("viper unmarshal failed, err:%v\n", err)
	}
	// 监听配置文件变化
	viper.WatchConfig()

	// 当使用结构体变量存储配置的时候，需要在配置发生变更后手动更新一下结构体变量
	viper.OnConfigChange(func(in fsnotify.Event) {
		log.Print("config has changed")
		if err := viper.Unmarshal(Conf); err != nil {
			log.Fatalf("viper unmarshal failed, err:%v\n", err)
		}
	})
	return nil
}

// GetEnvInfo read key from the environment variables.
func GetEnvInfo(key string) string {
	viper.AutomaticEnv()
	return viper.GetString(key)
}
